`include "global_def.h"

module Vertex(
  I_CLK,
  I_Opcode,
  I_VectorALUOut,
  I_LOCK,
  I_RAST_STALL,
  O_Opcode,
	O_Fragment_x0,
	O_Fragment_x1,
	O_Fragment_x2,
	O_Fragment_x3,
	O_Fragment_x4,
	O_Fragment_x5,
	O_Fragment_x6,
	O_Fragment_x7,
	O_Fragment_x8,
	O_Fragment_y0,
	O_Fragment_y1,
	O_Fragment_y2,
	O_Fragment_y3,
	O_Fragment_y4,
	O_Fragment_y5,
	O_Fragment_y6,
	O_Fragment_y7,
	O_Fragment_y8,
  O_Color0,
  O_Color1,
  O_Color2
);
input	I_CLK;
input I_LOCK;
input [`OPCODE_WIDTH-1:0] I_Opcode;
input [`VREG_WIDTH-1:0] I_VectorALUOut;
input I_RAST_STALL; //Stall from Rasterisation
output reg [`OPCODE_WIDTH-1:0] O_Opcode;
output reg [15:0] O_Fragment_x0;
output reg [15:0] O_Fragment_x1;
output reg [15:0] O_Fragment_x2;
output reg [15:0] O_Fragment_x3;
output reg [15:0] O_Fragment_x4;
output reg [15:0] O_Fragment_x5;
output reg [15:0] O_Fragment_x6;
output reg [15:0] O_Fragment_x7;
output reg [15:0] O_Fragment_x8;
output reg [15:0] O_Fragment_y0;
output reg [15:0] O_Fragment_y1;
output reg [15:0] O_Fragment_y2;
output reg [15:0] O_Fragment_y3;
output reg [15:0] O_Fragment_y4;
output reg [15:0] O_Fragment_y5;
output reg [15:0] O_Fragment_y6;
output reg [15:0] O_Fragment_y7;
output reg [15:0] O_Fragment_y8;
output reg [15:0] O_Color0;
output reg [15:0] O_Color1;
output reg [15:0] O_Color2;

reg [22:0] Row1[0:2];
reg [22:0] Row2[0:2];

reg [15:0] Row1Stack[0:5];
reg [15:0] Row2Stack[0:5];

reg [22:0] Vertex_x[0:8];
reg [22:0] Vertex_y[0:8];

reg [15:0] Color0;
reg [15:0] Color1;
reg [15:0] Color2;

genvar i;
integer j,k,stack;

reg [15:0] five;

initial begin
//	O_Fragment_x0 = 100;
//	O_Fragment_y0 = 100;
//	O_Fragment_x1 = 150;
//	O_Fragment_y1 = 100;
//	O_Fragment_x2 = 100;
//	O_Fragment_y2 = 150;
	
	O_Fragment_x3 = 300;
	O_Fragment_y3 = 300;
	O_Fragment_x4 = 350;
	O_Fragment_y4 = 250;
	O_Fragment_x5 = 400;
	O_Fragment_y5 = 300;
	
	O_Fragment_x6 = 175;
	O_Fragment_y6 = 75;
	O_Fragment_x7 = 250;
	O_Fragment_y7 = 125;
	O_Fragment_x8 = 125;
	O_Fragment_y8 = 400;
	
	Color0 = 0;
	Color1 = 0;
	Color2 = 0;
	
	stack = 0;
	
	for(j=0;j<9;j=j+1) begin
		Vertex_x[j] = 0;
		Vertex_y[j] = 0;
	end
	
	five = 16'h280;
end

reg [4:0] vertex_count;
initial vertex_count = 0;

wire [22:0] v0;
wire [22:0] v1;
wire [22:0] v2;
//wire [31:0] v3;
// 63:48 47:32 31:16 15:0
assign v0 = I_VectorALUOut[15:0];
assign v1 = I_VectorALUOut[31:16];
assign v2 = I_VectorALUOut[47:32];
//assign v3 = I_VectorALUOut[63:48];

wire [22:0] temp[0:3];
wire [22:0] temp2[0:35];
wire [15:0] temp3[0:17];
wire [15:0] temp4[0:17];
wire [15:0] temp6[0:9];
wire [15:0] temp7[0:4];

assign temp[0] = `mult(Row1[0],v1);
assign temp[1] = `mult(Row1[1],v2);
assign temp[2] = `mult(Row2[0],v1);
assign temp[3] = `mult(Row2[1],v2);

generate begin
	for (i=0;i<36;i=i+4) begin
		:mat
		assign temp2[i] = `mult(Row1[0],Vertex_x[i/4]);
		assign temp2[i+1] = `mult(Row1[1],Vertex_y[i/4]);
		assign temp2[i+2] = `mult(Row2[0],Vertex_x[i/4]);
		assign temp2[i+3] = `mult(Row2[1],Vertex_y[i/4]);
	end
	for (i=0;i<18;i=i+1) begin
		:mat2
		assign temp3[i] = `add(temp2[i*2],temp2[i*2+1]);
	end
	for (i=0;i<9;i=i+1) begin
		:mat3
		assign temp4[i*2] = `add(temp3[i*2],Row1[2]);
		assign temp4[i*2+1] = `add(temp3[i*2+1],Row2[2]);
	end
	
	assign temp7[4] = 32896;
	assign temp7[2] = `add(v0,temp7[4]);
	assign temp7[3][15] = !temp7[2][15];
	assign temp7[3][14:0] = temp7[2][14:0];
	
	assign temp6[0] = `mult(Row1[0],temp7[3]);
	assign temp6[2] = `mult(Row1[1],temp7[3]);
	assign temp6[4] = `mult(Row2[0],temp7[3]);
	assign temp6[6] = `mult(Row2[1],temp7[3]);
	
	assign temp6[1] = `mult(Row1[1],v0);
		
	assign temp7[0] = `mult(Row1[0],v0);
	assign temp6[3][15] = !temp7[0][15];
	assign temp6[3][14:0] = temp7[0][14:0];
		
	assign temp6[5] = `mult(Row2[1],v0);
	
	assign temp7[1] = `mult(Row2[0],v0);
	assign temp6[7][15] = !temp7[1][15];
	assign temp6[7][14:0] = temp7[1][14:0];
	
	assign temp6[8] = `add(temp[0],temp[1]);
	assign temp6[9] = `add(temp[2],temp[3]);
end
endgenerate

always @(negedge I_CLK)
begin
	if (!I_RAST_STALL) begin
		if (I_LOCK) begin
			O_Opcode <= I_Opcode;
			if(I_Opcode == `OP_SETCOLOR) begin
				if(vertex_count>=0 && vertex_count<3)
					Color0 <= 16'h0|(v0&16'h780)<<1|(v1&16'h780)>>3|(v2&16'h780)>>7;
				else if(vertex_count>=3 && vertex_count<6)
					Color1 <= 16'h0|(v0&16'h780)<<1|(v1&16'h780)>>3|(v2&16'h780)>>7;
				else
					Color2 <= 16'h0|(v0&16'h780)<<1|(v1&16'h780)>>3|(v2&16'h780)>>7;
			end
			else if(I_Opcode == `OP_LOADIDENTITY) begin
				Row1[0] <= 1<<7;Row1[1] <= 0;Row1[2] <= 0;
				Row2[0] <= 0;Row2[1] <= 1<<7;Row2[2] <= 0;
			end
			else if(I_Opcode == `OP_TRANSLATE) begin
				Row1[2] <= `add(temp[0],temp[1]);
				Row2[2] <= `add(temp[2],temp[3]);
			end 
			else if(I_Opcode == `OP_SCALE) begin
				Row1[0] <= temp[0];
				Row1[1] <= temp[1];
				Row2[0] <= temp[2];
				Row2[1] <= temp[3];
			end
			else if(I_Opcode == `OP_ROTATE) begin
				Row1[0] <= `add(temp6[0],temp6[1]);
				Row1[1] <= `add(temp6[2],temp6[3]);
				Row2[0] <= `add(temp6[4],temp6[5]);
				Row2[1] <= `add(temp6[6],temp6[7]);
			end
			else if(I_Opcode == `OP_SETVERTEX) begin
				
				Vertex_x[vertex_count] <= v1;
				Vertex_y[vertex_count] <= v2;
				
				vertex_count <= (vertex_count<8)?vertex_count+1:0;
			end
			else if(I_Opcode == `OP_ENDPRIMITIVE) begin
				O_Fragment_x0 <= (`add(temp4[0],five)*64)>>7;
				O_Fragment_y0 <= (`add(temp4[1],five)*64)>>7;

				O_Fragment_x1 <= (`add(temp4[2],five)*64)>>7;
				O_Fragment_y1 <= (`add(temp4[3],five)*64)>>7;

				O_Fragment_x2 <= (`add(temp4[4],five)*64)>>7;
				O_Fragment_y2 <= (`add(temp4[5],five)*64)>>7;

				O_Fragment_x3 <= (`add(temp4[6],five)*64)>>7;
				O_Fragment_y3 <= (`add(temp4[7],five)*64)>>7;

				O_Fragment_x4 <= (`add(temp4[8],five)*64)>>7;
				O_Fragment_y4 <= (`add(temp4[9],five)*64)>>7;

				O_Fragment_x5 <= (`add(temp4[10],five)*64)>>7;
				O_Fragment_y5 <= (`add(temp4[11],five)*64)>>7;

				O_Fragment_x6 <= (`add(temp4[12],five)*64)>>7;
				O_Fragment_y6 <= (`add(temp4[13],five)*64)>>7;

				O_Fragment_x7 <= (`add(temp4[14],five)*64)>>7;
				O_Fragment_y7 <= (`add(temp4[15],five)*64)>>7;

				O_Fragment_x8 <= (`add(temp4[16],five)*64)>>7;
				O_Fragment_y8 <= (`add(temp4[17],five)*64)>>7;
				
				O_Color0 <= Color0;
				O_Color1 <= Color1;
				O_Color2 <= Color2;
			end
			else if(I_Opcode == `OP_POPMATRIX) begin
				stack = stack - 3;
				for(j=0;j<3;j=j+1) begin
					Row1[j] <= Row1Stack[j+stack];
					Row2[j] <= Row2Stack[j+stack];
				end
			end
			else if(I_Opcode == `OP_PUSHMATRIX) begin
				for(j=0;j<3;j=j+1) begin
					Row1Stack[j+stack] <= Row1[j];
					Row2Stack[j+stack] <= Row2[j];
				end
				stack = stack + 3;
			end
		end
	end // if (!I_RAST_STALL)
end

endmodule